import json
import re
from abc import abstractmethod
from typing import Dict, NamedTuple

from langchain_core.output_parsers import BaseOutputParser


class AutoGPTAction(NamedTuple):
    """Action returned by AutoGPTOutputParser."""

    name: str
    args: Dict


# BaseLLMOutputParser --> BaseOutputParser --> BaseAutoGPTOutputParser
class BaseAutoGPTOutputParser(BaseOutputParser):
    """Base Output parser for AutoGPT."""

    @abstractmethod
    def parse(self, text: str) -> AutoGPTAction:
        """Return AutoGPTAction"""


def preprocess_json_input(input_str: str) -> str:
    """
    预处理字符串以便解析为 JSON

    将单个反斜杠替换为双反斜杠，
    同时保留已转义的反斜杠不变。

    Args:
        input_str: 待预处理的字符串

    Returns:
        预处理后的字符串
    """
    corrected_str = re.sub(
        r'(?<!\\)\\(?!["\\/bfnrt]|u[0-9a-fA-F]{4})', r"\\\\", input_str
    )
    return corrected_str

# BaseLLMOutputParser --> BaseOutputParser --> BaseAutoGPTOutputParser --> AutoGPTOutputParser
class AutoGPTOutputParser(BaseAutoGPTOutputParser):
    """Output parser for AutoGPT."""

    def parse(self, text: str) -> AutoGPTAction:
        try:
            parsed = json.loads(text, strict=False)
        except json.JSONDecodeError:
            preprocessed_text = preprocess_json_input(text)
            try:
                parsed = json.loads(preprocessed_text, strict=False)
            except Exception:
                return AutoGPTAction(
                    name="ERROR",
                    args={"error": f"Could not parse invalid json: {text}"},
                )
        try:
            return AutoGPTAction(
                name=parsed["command"]["name"],
                args=parsed["command"]["args"],
            )
        except (KeyError, TypeError):
            # 如果命令为空或者不完整
            return AutoGPTAction(
                name="ERROR",
                args={"error": f"Incomplete command args: {parsed}"}
            )